package server

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"gc-rds-ha/internal/common"
	msg "gc-rds-ha/scripts"
	"net/http"
	"os"
	"path"
	"strings"

	"google.golang.org/grpc/credentials/insecure"

	log "github.com/sirupsen/logrus"

	"google.golang.org/grpc/credentials"

	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"google.golang.org/grpc"
)

func (server *GcRdsHaServer) SwaggerRun(rmux *runtime.ServeMux) *http.ServeMux {
	mux := http.NewServeMux()
	mux.Handle("/", rmux)
	mux.HandleFunc("/swagger/", func(w http.ResponseWriter, r *http.Request) {
		if !strings.HasSuffix(r.URL.Path, "gcrdsha.swagger.json") {
			log.Printf("ServeSwaggerFile Not Found: %s", r.URL.Path)
			http.NotFound(w, r)
			return
		}
		p := strings.TrimPrefix(r.URL.Path, "/swagger/")
		// "../scripts/"为.swagger.json所在目录
		p = path.Join("../../scripts/", p)

		log.Printf("Serving swagger-file: %s", p)
		http.ServeFile(w, r, p)
	})
	mux.Handle("/swagger-ui/", http.StripPrefix(
		"/swagger-ui/",
		http.FileServer(
			http.Dir("../../internal/server/swagger/swagger-ui"),
		),
	),
	)
	return mux
}

func withOption() []grpc.DialOption {
	opts := make([]grpc.DialOption, 0)
	if common.AgentConfig.EnableTLS {
		opts = append(opts, withHttpTLS())
		return opts
	}
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
	return opts
}

func (server *GcRdsHaServer) HttpRun() {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	rmux := runtime.NewServeMux()
	//Start HTTP server (and proxy calls to gRPC server endpoint)
	err := msg.RegisterGcRdsHaHandlerFromEndpoint(ctx, rmux, fmt.Sprintf(":%d", common.AgentConfig.Rpc.Port), withOption())
	if err != nil {
		log.Fatalf("fail to RegisterGcRdsHaHandlerFromEndpoint: %v", err)
	}

	//{ // rpc客户端方式
	//	conn, err := grpc.Dial(fmt.Sprintf(":%d", common.AgentConfig.Rpc.Port), withOption()...)
	//	if err != nil {
	//		log.Fatalf("fail to dial: %v", err)
	//	}
	//	defer func(conn *grpc.ClientConn) {
	//		err := conn.Close()
	//		if err != nil {
	//			log.Fatalf("fail to conn.Close: %v", err)
	//		}
	//	}(conn)
	//	client := msg.NewGcRdsHaClient(conn)
	//	err = msg.RegisterGcRdsHaHandlerClient(ctx, rmux, client)
	//	if err != nil {
	//		log.Fatalf("RegisterGcRdsHaHandlerClient faild: %s", err)
	//	}
	//}

	mux := server.SwaggerRun(rmux)
	if err := startListen(mux); err != nil {
		log.Fatalf("startListen faild: %s", err)
	}
}
func startListen(m *http.ServeMux) error {
	if common.AgentConfig.EnableTLS {
		log.Print(common.AgentConfig.GcRdsHa.ServerPem, common.AgentConfig.GcRdsHa.ServerKey)
		return http.ListenAndServeTLS(fmt.Sprintf(":%d", common.AgentConfig.Http.Port), common.AgentConfig.GcRdsHa.ServerPem, common.AgentConfig.GcRdsHa.ServerKey, m)
	}
	return http.ListenAndServe(fmt.Sprintf(":%d", common.AgentConfig.Http.Port), m)
}

func withHttpTLS() grpc.DialOption {
	// 进行加载 key pair ,读取和解析公钥-私钥对并创建 X.509 密钥对
	cert, err := tls.LoadX509KeyPair(common.AgentConfig.GcRdsHa.ServerPem, common.AgentConfig.GcRdsHa.ServerKey)
	if err != nil {
		log.Println("加载 x509 证书失败!\n", err)
	}
	// 通过 CA 创建证书池
	certPool := x509.NewCertPool()

	// 向证书池中加入证书
	CAFileBytes, err := os.ReadFile(common.AgentConfig.GcRdsHa.Crt)
	if err != nil {
		log.Println("读取 ca.crt 证书失败!\n", err)
	}

	// 加载证书从 pem 文件里面，将来自 CA 的客户端证书附加到证书池中
	certPool.AppendCertsFromPEM(CAFileBytes)

	// 创建 credentials 对象，通过创建 TLS 凭证为所以传入的连接启用 TLS
	creds := credentials.NewTLS(&tls.Config{
		Certificates: []tls.Certificate{cert},        // 服务端证书
		ClientAuth:   tls.RequireAndVerifyClientCert, // 需要并且验证客户端证书
		RootCAs:      certPool,                       // 客户端证书池
		ServerName:   common.AgentConfig.GcRdsHa.CommonName,
	})
	return grpc.WithTransportCredentials(creds)
}
